home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume7 / cmstape < prev    next >
Encoding:
Internet Message Format  |  1986-11-30  |  44.0 KB

  1. Subject:  v07i008:  Read and write IBM VM/SP CMS dump tapes
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: Alan Crosswell <cybvax0!harvard!topaz!columbia!cucca!alan>
  6. Mod.sources: Volume 7, Issue 8
  7. Archive-name: cmstape
  8.  
  9. Following is a shar of a program that can read and write CMS tape dump
  10. tapes on both UNIX and CMS.
  11.  
  12. Alan Crosswell
  13. Columbia University
  14. alan@columbia.edu
  15.  
  16. #! /bin/sh
  17. # This is a shell archive, meaning:
  18. # 1. Remove everything above the #! /bin/sh line.
  19. # 2. Save the resulting text in a file.
  20. # 3. Execute the file with /bin/sh (not csh) to create:
  21. #    cmstape.1
  22. #    Makefile
  23. #    cmstape.c
  24. #    ebcdic.c
  25. # This archive created: Fri Jul 18 14:52:16 1986
  26. export PATH; PATH=/bin:/usr/bin:$PATH
  27. if test -f 'cmstape.1'
  28. then
  29.     echo shar: "will not over-write existing file 'cmstape.1'"
  30. else
  31. cat << \SHAR_EOF > 'cmstape.1'
  32. .TH CMSTAPE 1 "Columbia University"
  33. .SH NAME
  34. cmstape \- manipulate an IBM VM/SP CMS dump tape
  35. .SH SYNOPSIS
  36. .B cmstape
  37. [ -tvcrxfiud ] tape [ -Fnn ] file ... 
  38. .SH DESCRIPTION
  39. .I Cmstape
  40. manipulates an IBM VM/SP CMS dump tape.  Flags are:
  41. .TP 5
  42. .B \-t
  43. (default) type tape directory of tape file.
  44. .TP
  45. .B \-v
  46. verbose
  47. .TP
  48. .B \-c
  49. create a CMS tape dump.
  50. .TP
  51. .B \-r
  52. append to a CMS tape dump ('r' is non-mnemonic but matches tar).
  53. .TP
  54. .B \-x
  55. extract files from
  56. .I tape.
  57. If no names given all are extracted.
  58. otherwise only those named are extracted.  Syntax for names is: 
  59. .I fn.ft.
  60. .TP
  61. .B \-f
  62. .I tape
  63. is in readtape(1) format:  each file block is preceded by a two byte
  64. block length with vax byte ordering.  If ommitted,  /dev/nrmt8 is
  65. used.
  66. .TP
  67. .B \-i
  68. image (no EBCDIC/ASCII translation or tacking on of newlines).  Handled
  69. differently under UNIX and CMS:  Under UNIX,  V-format files
  70. are extracted with a halfword length header preceding each
  71. record.  This makes image extracts and creates a reversible process
  72. for V as well as F format files under UNIX.  Under CMS, V-format
  73. files are written to the CMS filesystem which maintains the record
  74. length information,  so no length headers are needed in the data.
  75. .TP
  76. .B \-u
  77. don't convert filenames to lowercase and vice-versa.  By default,
  78. lowercase UNIX names become uppercase CMS names and vice-versa.
  79. .TP
  80. .B \-d
  81. debug (multiple occurences increase volume of output).
  82. .PP
  83. .I Cmstape
  84. reads and writes either a tape device or a file that has been
  85. read off a tape by readtape(l). (That is,  a file that contains
  86. a 2 byte vax order tape block size before each data block).
  87. This allows you to get the files off a tape with readtape(l)
  88. and transfer them over the network to the system where they will
  89. actually be extracted.  You can also do the opposite:  create
  90. a tape dump file,  transfer it over the network,  and write it
  91. to a tape device with writetape(l).
  92. .PP
  93. When writing a tape dump under UNIX,  file names preceded by
  94. .BI \-F "nn"
  95. cause those files to be written in fixed instead of the default variable 
  96. format. If
  97. .I nn
  98. is specified,  it will be used for the record length, otherwise 80 is assumed.
  99. Under CMS, this switch is ignored;  the actual record length and format
  100. maintained by the filesystem are used.
  101. .SH FILES
  102. .TP 25
  103. cms??????
  104. temporary UNIX work file.
  105. .TP
  106. CMSTAPE.CMSUT1
  107. temporary CMS work file.
  108. .SH EXAMPLES
  109. Get directory of a CMS tape mounted on your favorite UNIX system:
  110. .nf
  111. .sp
  112.     % cmstape -tv
  113.     F/80         46 Apr  2 17:51 EXPCPU   ASSEMBLE A1
  114.     V/70         43 Apr  2 18:07 AUTHORIZ EXEC     A1
  115.     V/34         40 Jun 11 12:40 SENDCTLS EXEC     A1
  116.     V/50         56 Apr 17 14:43 MKTOOLS  EXEC     A1
  117.     V/76         95 Jun 11 12:39 CW       EXEC     A1
  118. .fi
  119. .PP
  120. Extract all files from a CMS tape:
  121. .nf
  122. .sp
  123.     % cmstape -x
  124. .fi
  125. .PP
  126. Create a CMS tape dump on your UNIX system to give to your
  127. poor friend forced to use CMS:
  128. .nf
  129. .sp
  130.     % cmstape -c /dev/nrmt8 cmstape.c -F foo.assemble
  131. .fi
  132. .PP
  133. Read a CMS tape dump on your UNIX system,  send it over the network
  134. to your CMS system and extract the files there:
  135. .nf
  136. .sp
  137.     % readtape
  138.     Reading from /dev/nrmt0
  139.     Writing to file1    123456 bytes.
  140.     Writing to file2         0 bytes.
  141.     % telnet ibmhost
  142.     ftp vaxhost
  143.     ...
  144.     ftp> type i
  145.     ftp> get file1 file1.file
  146.     ftp> quit
  147.     cmstape -xfi file1    
  148. .fi
  149. .SH SEE ALSO
  150. readtape(1), writetape(1) by Jim Guyton, Rand Corp.
  151. .SH AUTHOR
  152. .nf
  153. E. Alan Crosswell
  154. Columbia University
  155. .fi
  156. .SH BUGS
  157. Due to the odd format of CMS tape files,  you will need twice the working
  158. space as that taken up by the final files.  Also,  even files you don't
  159. want to extract get copied to a temporary file and are then discarded
  160. since the name of the file is at the end of the data!
  161. .PP
  162. Only manipulates files under CMS;  use the CMS TAPE command for
  163. tape devices.
  164. .PP
  165. Does not know about CMS VMFPLC2 format.
  166. SHAR_EOF
  167. fi
  168. if test -f 'Makefile'
  169. then
  170.     echo shar: "will not over-write existing file 'Makefile'"
  171. else
  172. cat << \SHAR_EOF > 'Makefile'
  173. OBJS = cmstape.o ebcdic.o
  174. CFLAGS = -O
  175. cmstape:    $(OBJS)
  176.     $(CC) -o cmstape $(OBJS)
  177. cmstape.o:    cmstape.c
  178. ebcdic.o:    ebcdic.c
  179.  
  180. install:    cmstape
  181.     install -s cmstape /usr/local
  182.     cp cmstape.1 /usr/man/manl/cmstape.l
  183. clean:
  184.     rm -f *.o
  185.  
  186. SHAR_EOF
  187. fi
  188. if test -f 'cmstape.c'
  189. then
  190.     echo shar: "will not over-write existing file 'cmstape.c'"
  191. else
  192. cat << \SHAR_EOF > 'cmstape.c'
  193. /* $Header: cmstape.c,v 1.1 86/07/18 10:44:17 alan Rel $
  194.  *
  195.  * NAME
  196.  *    CMSTAPE - manipulate a CMS TAPE DUMP tape.
  197.  *
  198.  * SYNOPSIS
  199.  *    cmstape [-tvcrxfiud] tape [-Fnn] file...
  200.  *
  201.  * DESCRIPTION
  202.  *
  203.  *    Cmstape manipulates an IBM CMS tape.  Flags are:
  204.  *     -t (default) type tape directory of tape file.
  205.  *     -v verbose
  206.  *     -c create a CMS tape dump
  207.  *     -r append to a CMS tape dump ('r' is non-mnemonic but matches tar)
  208.  *     -x extract files from tape.  If no names given all are extracted.
  209.  *        otherwise only those named are extracted.  Syntax for names is: fn.ft
  210.  *     -f tape is in readtape(1) format: each file block is preceded by
  211.  *        a two byte block length.
  212.  *     -i image (no translation or tacking on of newlines).  For V-format files
  213.  *        the extracted/written file includes a halfword length preceding each
  214.  *        record.  This makes image extracts and creates a reversible process
  215.  *        for V as well as F format files.
  216.  *     -u don't convert filenames to lowercase and vice-versa
  217.  *     -d debug (multiple occurences increase volume of output)
  218.  *
  219.  *    Reads either from a tape device or from files that have been
  220.  *    read off a tape by readtape(l).  That is,  files that contain
  221.  *    a 2 byte tape block size before each data block (with vax
  222.  *    swapped byte ordering!).
  223.  *
  224.  *    When writing a tape dump,  file names preceded by "-Fnn" cause those
  225.  *    files to be written in fixed instead of the default variable format.
  226.  *    If "nn" is specified,  it will be used for the record length, otherwise
  227.  *    80 is assumed.
  228.  *
  229.  * BUGS
  230.  *    Due to the odd format of CMS tape files,  you will need twice the working
  231.  *    space as that taken up by the final files.  Also,  even files you don't
  232.  *    want to extract get copied to a temporary file and are then discarded
  233.  *    since the name of the file is at the end of the data!
  234.  *
  235.  * FILES
  236.  *    cms??????          temporary work file.
  237.  *    CMSTAPE.CMSUT1     temporary work file when CMS #defined.
  238.  *
  239.  * SEE ALSO
  240.  *    IBM VM/SP Data Areas and Control Block Logic, LY20-0891
  241.  *
  242.  *    Readtape, writetape utilities:  Jim Guyton, Rand Corp.
  243.  *
  244.  * AUTHOR
  245.  *    E. Alan Crosswell
  246.  *    Columbia University
  247.  *    alan@columbia.edu
  248.  *
  249.  * #define CMS when compiling for Waterloo C under CMS.
  250.  *
  251.  * COMPILATION INSTRUCTIONS
  252.  *  4.x BSD:
  253.  *    cc -o cmstape cmstape.c ebcdic.c
  254.  *  Waterloo C/370:
  255.  *    cw cmstape (prm CMS 1
  256.  *    linkc cmstape
  257.  *
  258.  * You may wonder why I wrote this.  It's simple:  I get a lot of CMS tapes
  259.  * in the mail.  The IBM machine room is across campus but the vax is just
  260.  * down the hall and they're both on the network.  Here's how I do it:
  261.  *    1) mount the tape on the vax and use readtape to read all the files
  262.  *       into a directory.
  263.  *    2) login on the IBM and FTP the files from the vax in image mode:
  264.  *       ftp thevax
  265.  *       login me
  266.  *       represent i
  267.  *       get file1 file1.file
  268.  *       get file2 file2.file
  269.  *         etc.
  270.  *    3) crank up cmstape on the IBM:
  271.  *       cmstape -xvfi file1
  272.  *       cmstape -xvfi file2
  273.  *         etc.
  274.  *
  275.  * $Log:    cmstape.c,v $
  276.  * Revision 1.1  86/07/18  10:44:17  alan
  277.  * Initial revision
  278.  * 
  279.  */
  280.  
  281.  
  282. /* various header files */
  283.  
  284. #ifdef IBM370                   /* future version of Wloo C may predefine it */
  285. # define CMS 1
  286. #endif IBM370
  287.  
  288. #include <stdio.h>
  289. #include <ctype.h>
  290. #ifdef CMS
  291. # include <time.h>
  292. # include <file.h>
  293. # include <stdlib.h>
  294. # include <string.h>
  295. # include <types.h>
  296. # include <stat.h>
  297. #else
  298. # include <strings.h>
  299. # include <sys/time.h>
  300. # include <sys/types.h>
  301. # include <sys/file.h>
  302. # include <sys/stat.h>
  303. #endif CMS
  304.  
  305. /*
  306.  * Format of a CMS TAPE DUMP tape entry for each file:
  307.  *
  308.  * 1) One or more blocks like this:
  309.  *      +--+-+-+-+-+-+-+-----/ /-+-+-+-----
  310.  *      |02|C M S V| l | data... | l | data...
  311.  *      +--+-+-+-+-+-+-+-----/ /-+-+-+-----
  312.  *       <-----------4101 bytes max---------->
  313.  *
  314.  *    or this (for fixed records (lrecl in the FST)):
  315.  *      +--+-+-+-+-+-----/ /-+-+-+-----
  316.  *      |02|C M S F| data... | l | data...
  317.  *      +--+-+-+-+-+-----/ /-+-+-+-----
  318.  *       <-----------4101 bytes max---------->
  319.  *
  320.  * 2) Followed by an ending FST + filename
  321.  *      +--+-+-+-+-+------------+
  322.  *      |02|C M S N|  FST data  |
  323.  *      +--+-+-+-+-+------------+
  324.  *       <-------87 bytes------>
  325.  *
  326.  * There are a whole bunch of other CMSx letters as well but I don't know
  327.  * what they mean and have never seen one on a tape I've received.  Some
  328.  * have to do with sparse files.
  329.  *
  330.  * Many CMS files may be in a single physical tape file.  Notice that since
  331.  * the FST comes after the data,  there is no way to know the record length
  332.  * of "F" (fixed) files until after the entire file has been read.
  333.  * "V" (variable) files have the length of each record in front of
  334.  * the record.
  335.  *
  336.  * The tape fst written into the CMSN block is actually the CMS fst starting
  337.  * a few words from the beginning,  then some filler,  then the filename.
  338.  */
  339.  
  340. #ifdef CMS
  341. typedef unsigned char u_char;
  342. #endif CMS
  343. typedef struct {
  344.     u_char f_wp[2];             /* write pointer - IBM byte ordering */
  345.     u_char f_rp[2];             /* read pointer */
  346.     u_char f_mode[2];           /* mode */
  347.     u_char f_itcnt[2];          /* item count */
  348.     u_char f_fcl[2];            /* first chain link */
  349.     u_char f_recfm;             /* record format: F or V */
  350.     u_char f_flag;              /* flag */
  351.     u_char f_lrecl[4];          /* record length */
  352.     u_char f_blkcnt[2];         /* data block count */
  353.     u_char f_date[6];           /* date FYFYMMDDHHNN */
  354.     u_char f_fop[4];            /* file origin pointer */
  355. /* beginning of alternate counts (added with EDF file system) */
  356.     u_char f_ablkcnt[4];        /* alternate block count */
  357.     u_char f_areccnt[4];        /* alternate record count */
  358.     u_char f_nlvl;              /* number of ptr block levels */
  359.     u_char f_ptrs;              /* fst pointer size */
  360.     u_char f_adate[6];          /* alternate date YYMMDDHHNNSS */
  361.     u_char f_filler[20];        /* fill out to 64 bytes */
  362. /* filename tacked on after fst */
  363.     u_char f_fn[8];
  364.     u_char f_ft[8];
  365.     u_char f_fm[2];
  366. } tapefst;                      /* overall length 82 bytes */
  367.  
  368. /* what's at the beginning of each tape block */
  369. typedef struct {
  370.     u_char cms[4];              /* 02 CMS */
  371.     u_char fmt;                 /* F | V | N | ... */
  372. } tapehead;
  373.  
  374. #define F 0xc6                  /* fixed */
  375. #define V 0xe5                  /* variable */
  376. #define N 0xd5                  /* end of file */
  377.  
  378.  
  379. /* macros for ebcdic to local character set and byte ordering */
  380. #ifdef CMS
  381. # define ETOL(c) (c)
  382. # define LTOE(c) (c)
  383. #else
  384. extern char etoa[], atoe[];
  385. # define ETOL(c) (etoa[(c)&0xff])
  386. # define LTOE(c) (atoe[(c)&0xff])
  387. #endif CMS
  388. #define IBMTOINT(x) (((x[0]&0xff)<<24) + ((x[1]&0xff)<<16) \
  389.                      + ((x[2]&0xff)<<8) + (x[3]&0xff))
  390. #define IBMTOSHORT(x) (((x[0]&0xff)<<8) + (x[1]&0xff))
  391. #define INTTOIBM(a,b) a[0]=(b>>24)&0xff, a[1]=(b>>16)&0xff, \
  392.                      a[2]=(b>>8)&0xff, a[3]=(b&0xff)
  393. #define SHORTTOIBM(a,b) a[0]=(b>>8)&0xff, a[1]=(b&0xff)
  394.  
  395. /* hi and lo nibbles of a byte (packed decimal) */
  396. #define HI(x) ((x)>>4)
  397. #define LO(x) ((x)&0x0f)
  398. #define PACK(x) (((((x)/10)&0xf) << 4) | (((x)%10)&0xf))
  399.  
  400. /* Globals */
  401.  
  402.  
  403. #define MAXBUF 1<<16            /* max size file record */
  404. #define DEFTAPE "/dev/nrmt8"    /* default tape name */
  405. #define TAPEDATA 4096           /* size of data part of tape block */
  406.  
  407. static int Fflag = 0;           /* indicates readtape(l) file */
  408. static int Tflag = 0;           /* just give a directory */
  409. static int Vflag = 0;           /* verbose */
  410. static int Xflag = 0;           /* read files off tape */
  411. static int Cflag = 0;           /* write files onto tape */
  412. static int Rflag = 0;           /* append files onto tape */
  413. static int Iflag = 0;           /* image mode (instead of text) */
  414. static int Uflag = 0;           /* uppercase converted file names */
  415. static int Debug = 0;           /* debug */
  416. static char *Tapename = NULL;   /* tape file name */
  417. static char **Fname = NULL;     /* ptr to array of file names */
  418. static int Fcount = 0;          /* number in above array */
  419. static char *Cmdname;           /* name invoked as */
  420. static char *Bufp = NULL;       /* buffer pointer */
  421. static int Lrecl = 0;           /* record length */
  422. #ifdef CMS
  423. static struct stat St;          /* used for CMS tape dumps */
  424. static char Tempname[] = "cmstape.cmsut1 (bin lrecl 65535";
  425. #else
  426. static char Template[] = "cmsXXXXXX";
  427. static char Tempname[sizeof(Template)];
  428. #endif CMS
  429. static FILE *Tempf = NULL;      /* shared by dodata and doeof */
  430. struct nametab {                /* ebcdic name table */
  431.     char name[16];
  432. } *Nametab = NULL;
  433.  
  434. static char CMSh[] = {0x02, 0xc3, 0xd4, 0xe2 };
  435.                     /*  02    C     M     S  */
  436.  
  437. static char *Month[12] = {
  438.     "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
  439.     "Sep", "Oct", "Nov", "Dec" };
  440.  
  441. /* shared by dumprec and dumpeof */
  442. static char Tapebuf[TAPEDATA+sizeof(tapehead)];
  443. static char *Tbp;               /* ptr into tapebuf */
  444. static int Tbrem;               /* remainder length */
  445. static int Recs;                /* records dumped */
  446. static int Blocks;              /* blocks dumped */
  447. static int Maxrecl;             /* max lrecl */
  448.  
  449.  
  450. /*
  451.  * the main program.  All the work is done in readtape() and writetape()
  452.  * (not to be confused with tape utilities of the same name).
  453.  */
  454. main(argc, argv)
  455. {
  456.     options(argc, argv);        /* parse options */
  457.     initialize();               /* intialize junk */
  458.     if (Cflag)
  459.       writetape();              /* output */
  460.     else
  461.       readtape();               /* input */
  462.     exit(0);
  463. }
  464.  
  465. static
  466. options(argc, argv)             /* parse options */
  467. int argc;
  468. char **argv;
  469. {
  470.     Cmdname = argv[0];
  471.     for(--argc, ++argv; argc > 0 && argv[0][0] == '-'; argc--, argv++) {
  472.         char *cp = argv[0];
  473.         while (*++cp) switch(*cp) {
  474.           case 'f':
  475.             Fflag++;
  476.             continue;
  477.           case 't':
  478.             Tflag++;
  479.             continue;
  480.           case 'v':
  481.             Vflag++;
  482.             Tflag++;
  483.             continue;
  484.           case 'x':
  485.             Xflag++;
  486.             continue;
  487.           case 'c':
  488.             Cflag++;
  489.             continue;
  490.           case 'i':
  491.             Iflag++;
  492.             continue;
  493.           case 'd':
  494.             Debug++;
  495.             continue;
  496.           case 'u':
  497.             Uflag++;
  498.             continue;
  499.           case 'r':
  500.             Cflag++;
  501.             Rflag++;
  502.             continue;
  503.           default:
  504.             usage();
  505.         }
  506.     }
  507.     Tapename = (argc--)? *argv++ : DEFTAPE;
  508.     if (argc > 0) {
  509.         Fname = argv;
  510.         Fcount = argc;
  511.     }
  512.     if (Xflag+Cflag == 0)
  513.       Tflag = 1;
  514.     else if (Xflag+Cflag > 1) {
  515.         fprintf(stderr,"%s: Can't extract and create at the same time!\n",
  516.                 Cmdname);
  517.         exit(1);
  518.     }
  519.     if (Debug)
  520.       printoptions();
  521. }
  522.  
  523. /*
  524.  * get a buffer for I/O and build table of file names
  525.  */
  526. static
  527. initialize()
  528. {
  529.     char *malloc(), *unix2cms();
  530.  
  531. #ifdef CMS
  532.     setiomsg(1);
  533. #endif CMS
  534.     if ((Bufp = malloc(MAXBUF+2)) == NULL) /* get a buffer */
  535.       croak("malloc");
  536.     if (Fcount && (Cflag || Xflag)) { /* user gave list of names */
  537.         int i;
  538.  
  539.         if ((Nametab = (struct nametab *)malloc(Fcount * sizeof(Nametab[0])))
  540.             == NULL)
  541.           croak("malloc");
  542.         if (Debug > 1)
  543.           fprintf(stderr,"Name table:\n");
  544.         for (i = 0; i < Fcount; i++) {
  545.             bcopy(unix2cms(Fname[i]),Nametab[i].name,sizeof(Nametab[0].name));
  546.             if (Debug > 1) {
  547.                 int j;
  548.                 for (j = 0; j < sizeof(Nametab[0].name); j++)
  549.                   fputc(ETOL(Nametab[i].name[j]), stderr);
  550.                 fputc('\n', stderr);
  551.             }
  552.         }
  553.     }
  554. }
  555.  
  556. static
  557. printoptions()                  /* print out options */
  558. {
  559.     int i;
  560.  
  561.     fprintf(stderr,"%s: switches: ", Cmdname);
  562.     if (Fflag) fputc('f',stderr);
  563.     if (Tflag) fputc('t',stderr);
  564.     if (Xflag) fputc('x',stderr);
  565.     if (Cflag) fputc('c',stderr);
  566.     if (Iflag) fputc('i',stderr);
  567.     if (Uflag) fputc('u',stderr);
  568.     if (Vflag) fputc('v',stderr);
  569.     if (Rflag) fputc('r',stderr);
  570.     if (Debug) fputc('d',stderr);
  571.     fprintf(stderr,"\n\ttape '%s'\n", Tapename);
  572.     if (Fcount) {
  573.         fprintf(stderr,"\t%d files:", Fcount);
  574.         for (i = 0; i < Fcount; i++)
  575.           fprintf(stderr, " %s", Fname[i]);
  576.         fprintf(stderr,".\n");
  577.     }
  578. }
  579.  
  580. static
  581. usage()
  582. {
  583.     fprintf(stderr,"%s: Usage: %s [-ftvxcdiu] tape name...\n", Cmdname,
  584.             Cmdname);
  585.     exit(1);
  586. }
  587.  
  588. static
  589. readtape()                      /* read a cms format tape */
  590. {
  591.     int tapefd;
  592.     int len;
  593.     tapehead *t = (tapehead *)Bufp;
  594.     char *dp = Bufp + sizeof(*t);
  595. #undef NAME
  596. #ifdef CMS
  597. # define NAME wlooname
  598.     char wlooname[100];
  599.     strcpy(wlooname,Tapename);
  600.     strcat(wlooname,"(bin");
  601. #else
  602. # define NAME Tapename
  603. #endif CMS
  604.     if ((tapefd = open(NAME, O_RDONLY)) < 0)
  605.       croak(Tapename);
  606.  
  607.     while ((len = readblock(tapefd)) > 0) {
  608.         if (Debug > 1)
  609.           fprintf(stderr,"readblock return len=%d\n", len);
  610.         if (len < sizeof(tapehead) || bcmp(t->cms,CMSh,sizeof(CMSh)))
  611.           die("%s: not a CMS tape\n", Tapename);
  612.         len -= sizeof(*t);      /* subtract length of header */
  613.         switch (t->fmt) {
  614.           case N:               /* EOF */
  615.             doeof(dp,len);
  616.             break;
  617.           case F:               /* F data */
  618.           case V:               /* V data */
  619.             if (Xflag)
  620.               dodata(dp,len);   /* copy the data and fix it up later */
  621.             break;
  622.           default:
  623.             die("%s: CMS format %c not supported.\n",
  624.                     Tapename, ETOL(t->fmt));
  625.         }
  626.     }
  627.  
  628. }
  629.  
  630. /*
  631.  * copy the data verbatim to the temp file.
  632.  */
  633. dodata(b,l)
  634. char *b;
  635. int l;
  636. {
  637.     if (Debug > 1) {
  638.         fprintf(stderr,"data block, len=%d\n", l);
  639.         if (Debug > 2)
  640.           dump(b-sizeof(tapehead),l+sizeof(tapehead));
  641.     }
  642.     if (Tempf == NULL) {        /* first time thru */
  643. #ifndef CMS
  644.         strcpy(Tempname,Template);
  645.         mktemp(Tempname);
  646. #endif
  647.         Tempf = fopen(Tempname,"w+");
  648.         if (Tempf == NULL)
  649.           croak(Tempname);
  650.     }
  651.     if (fwrite(b, l, 1, Tempf) == NULL)
  652.       croak(Tempname);
  653. }
  654.  
  655. char *cms2unix();
  656.  
  657. /*
  658.  * process the EOF block.  Depending on options selected:
  659.  *   - copy the temp file using the recfm and lrecl with possible translations.
  660.  *   - type out the fst info in a manner similar to ls.
  661.  */
  662. static
  663. doeof(b,l)
  664. tapefst *b;
  665. int l;
  666. {
  667.     if (Debug) {
  668.         fprintf(stderr,"EOF block, len=%d\n", l);
  669.         prtfst(b);
  670.     }
  671.     if (l < sizeof(tapefst))
  672.       die("%s: file label too short.\n", Tapename);
  673.     Lrecl = IBMTOINT(b->f_lrecl);
  674.     if (in_nametab(b)) {
  675.         if (Tflag)
  676.           prinfo(b);
  677.         if (Xflag) {            /* actually reading the data */
  678.             if (Tempf == NULL) {
  679.                 fprintf(stderr,"%s: Empty file.  Skipping...\n",Tapename);
  680.                 return;
  681.             }
  682. #ifndef CMS
  683.             if (Iflag) {        /* when not CMS, this is simply a rename */
  684.                 fclose(Tempf);
  685.                 Tempf = NULL;
  686.                 if (rename(Tempname, cms2unix(b)) < 0)
  687.                   perror(Tempname);
  688.                 return;
  689.             }
  690. #endif CMS
  691.             /* call V_ or F_close for cooked files always and image files
  692.                when under CMS.  Image files under unix were handled above. */
  693.             if (b->f_recfm == V)
  694.               V_close(b);
  695.             else
  696.               F_close(b);
  697.         }
  698.     } /* end if in Nametab[] */
  699.     if (Xflag && Tempf != NULL) { /* clean up when not in Nametab[] */
  700.         fclose(Tempf);
  701.         Tempf = NULL;
  702.         if (!Debug)
  703.           unlink(Tempname);
  704.         else
  705.           fprintf(stderr,"%s: not unlinked (debug)\n", Tempname);
  706.     }
  707. }
  708.  
  709. static
  710. prinfo(b)
  711. tapefst *b;
  712. {
  713.     int lrecl, reccnt, year, mon, day, hour, min;
  714.     int i;
  715.     struct tm *tp;
  716.     long tic;
  717.  
  718.     if (Vflag) {
  719.         lrecl = IBMTOINT(b->f_lrecl);
  720.         reccnt = IBMTOINT(b->f_areccnt);
  721.         year = HI(b->f_adate[0]) * 10 + LO(b->f_adate[0]);
  722.         mon =  HI(b->f_adate[1]) * 10 + LO(b->f_adate[1]);
  723.         day =  HI(b->f_adate[2]) * 10 + LO(b->f_adate[2]);
  724.         hour = HI(b->f_adate[3]) * 10 + LO(b->f_adate[3]);
  725.         min =  HI(b->f_adate[4]) * 10 + LO(b->f_adate[4]);
  726. #ifdef CMS
  727.         tp = localtime();       /* waterloo goofed! */
  728. #else
  729.         time(&tic);
  730.         tp = localtime(&tic);
  731. #endif CMS
  732.         printf("%c/%-4d %8d %s %2d ",ETOL(b->f_recfm),
  733.                lrecl, reccnt, Month[mon-1], day);
  734.         if (tp->tm_year != year)
  735.           printf(" %4d", year);
  736.         else
  737.           printf("%2d:%02d ",hour,min);
  738.     }
  739.     for (i = 0; i < 8; i++)
  740.       putchar(ETOL(b->f_fn[i]));
  741.     putchar(' ');
  742.     for (i = 0; i < 8; i++)
  743.       putchar(ETOL(b->f_ft[i]));
  744.     putchar(' ');
  745.     putchar(ETOL(b->f_fm[0]));
  746.     putchar(ETOL(b->f_fm[1]));
  747.     putchar('\n');
  748. }
  749.  
  750.  
  751. /* V format close.  Rewind the temp file and write the final file */
  752. static
  753. V_close(fst)
  754. tapefst *fst;
  755. {
  756.     int newfd = FVcreat('v',fst);
  757.     int len;
  758.  
  759.     rewind(Tempf);
  760.     Recs = 0;
  761.     while (fread(Bufp, 2, 1, Tempf)) { /* get length header */
  762.         len = IBMTOSHORT(Bufp);
  763.         if (fread(Bufp, len, 1, Tempf) == 0) /* get data */
  764.           croak(Tempname);
  765.         writerec(newfd, Bufp, len); /* write out record */
  766.     }
  767.     close(newfd);
  768. }
  769.  
  770. /* F format close.  Close the temp file, f and rewrite the final
  771.    F format file by calling writerec. */
  772. static
  773. F_close(fst)
  774. tapefst *fst;
  775. {
  776.     int newfd = FVcreat('f',fst);
  777.  
  778.     rewind(Tempf);
  779.     Recs = 0;
  780.     while (fread(Bufp, Lrecl, 1, Tempf)) { /* get record */
  781.         writerec(newfd, Bufp, Lrecl); /* and write it */
  782.     }
  783.     close(newfd);
  784. }
  785.  
  786. static int
  787. FVcreat(recfm,fst)              /* creat final output file */
  788. char recfm;
  789. tapefst *fst;
  790. {
  791.     int newfd;
  792.     char *newname = cms2unix(fst);
  793. #undef NAME
  794. #ifdef CMS
  795. # define NAME wlooname
  796.     char wlooname[100];
  797.  
  798.     sprintf(wlooname,"%s (%s recfm %c lrecl %d", newname,
  799.             (Iflag)?"raw bin":"", recfm, Lrecl);
  800. #else
  801. # define NAME newname
  802. #endif CMS
  803.  
  804.     if ((newfd = creat(NAME,0644)) < 0)
  805.       croak(NAME);
  806.     return newfd;
  807. }
  808.  
  809. /*
  810.  * write record out. Check flags and do ebcdic->ascii translation
  811.  * and adding newline, etc.  When the file is opened "raw" under CMS,
  812.  * each write() call is guaranteed to write a CMS record.
  813.  */
  814. static
  815. writerec(fd,b,l)                /* write a record out to file fd */
  816. int fd;
  817. char *b;
  818. int l;
  819. {
  820.     register int i;
  821.  
  822.     ++Recs;
  823.     if (!Iflag) {               /* text copy */
  824.         if (l == 1 && *b == LTOE(' ')) /* null line */
  825.           l = 0;
  826.         for (i = 0; i < l; i++) /* translate it */
  827.           b[i] = ETOL(b[i]);
  828.         b[l++] = '\n';          /* and add newline */
  829.     }
  830.     if (Debug > 1) {
  831.        fprintf(stderr,"writerec: record %5d length %d:", Recs, l);
  832.        dump(b,l);
  833.     }
  834.     if (write(fd,b,l) != l)
  835.       croak("writerec");
  836. }
  837.  
  838. /*
  839.  * convert CMS to Unix name:  "AAA     BBB     A1" becomes "aaa.bbb"
  840.  * if Uflag, don't alter case.
  841.  */
  842. static char *
  843. cms2unix(fst)
  844. tapefst *fst;
  845. {
  846.     static char name[20];
  847.     char *np = name, c;
  848.     int i;
  849.  
  850.     for (i = 0; i < 8 && (c = ETOL(fst->f_fn[i])) != ' '; i++)
  851.       *np++ = (!Uflag && isupper(c)) ? tolower(c) : c;
  852.     *np++ = '.';
  853.     for (i = 0; i < 8 && (c = ETOL(fst->f_ft[i])) != ' '; i++)
  854.       *np++ = (!Uflag && isupper(c)) ? tolower(c) : c;
  855.     *np = '\0';
  856.     if (Debug > 1)
  857.       fprintf(stderr,"cms2unix: %s\n", name);
  858.     return name;
  859. }
  860.  
  861. /*
  862.  * unix2cms: Convert unix name of /1/2/3/aaa.bbb to 16 character ebcdic string
  863.  * of "AAA     BBB     " for comparisons with fn ft.  If Uflag, don't
  864.  * alter case.
  865.  */
  866. static char *
  867. unix2cms(f)                     /* convert unix name string to CMS */
  868. char *f;
  869. {
  870.     static char name[17];
  871.     char *p,*np = name;
  872.     int i;
  873.  
  874.     f = (p = rindex(f,'/')) ? p+1 : f; /* skip leading path components */
  875.     /* filename */
  876.     for (i = 0; i < 8 && *f != '.' && *f != '\0'; i++, f++, np++)
  877.       *np = LTOE((!Uflag && islower(*f)) ? toupper(*f) : *f);
  878.     for (; i < 8; i++, np++)
  879.       *np = LTOE(' ');          /* pad out to 8 */
  880.  
  881.     /* filetype */
  882.     if (*f == '\0')
  883.       f = "file";               /* fill it in with "FILE" */
  884.     else
  885.       f++;
  886.     for (i = 0; i < 8 && *f != '.' && *f != '\0'; i++, f++, np++)
  887.       *np = LTOE((!Uflag && islower(*f)) ? toupper(*f) : *f);
  888.     for (; i < 8; i++, np++) /*  */
  889.       *np = LTOE(' ');          /* pad out to 8 */
  890.     name[16] = '\0';
  891.     return name;
  892. }
  893.  
  894. /*
  895.  * readblock - read a tape block into the Bufp buffer.
  896.  * If Fflag,  then the tape is actually a disk file created by readtape(l)
  897.  * which has a 16 bit block length prior to each data block.
  898.  * If reading straight from a tape device,  the read sys call will
  899.  * hopefully return the physical block length.  In either case,
  900.  * set *bpp to point to the beginning of the data and return the data
  901.  * length.
  902.  */
  903. static
  904. readblock(fd)                   /* read a tape block */
  905. int fd;
  906. {
  907.     int nread;
  908.  
  909.     if (Fflag)
  910.       return read_with_len(fd);
  911.     else {
  912.         nread = read(fd, Bufp, MAXBUF); /* try for the max */
  913.         if (Debug > 2)
  914.           fprintf(stderr,"physical block size %d\n", nread);
  915.         if (nread < 0)
  916.           croak(Tapename);
  917.         return nread;
  918.     }
  919. }
  920.  
  921. static
  922. read_with_len(fd)               /* read a readtape(l) format block */
  923. int fd;
  924. {
  925.     char bytes[2];
  926.     int blen;
  927.     int nread;
  928.     int amt;
  929.     char *bp;
  930.  
  931.     /* read the 2 byte readtape(l) block length prefix */
  932.     nread = read(fd, bytes, 2);
  933.     if (nread == 0)
  934.       return 0;                 /* EOF */
  935.     if (nread < 0)
  936.       croak(Tapename);
  937.     if (nread != 2)
  938.       die("%s: unexpected EOF reading block length (%d)\n",
  939.           Tapename, nread);
  940.     blen = ((unsigned)bytes[1] << 8) + (unsigned)bytes[0];
  941.     if (Debug > 2)
  942.       fprintf(stderr,"readtape block length [%d,%d] %d\n",
  943.               bytes[0], bytes[1], blen);
  944.     if (blen == 0)
  945.       return 0;         /* empty block == EOF */
  946.     if (blen > MAXBUF) {
  947.         fprintf(stderr,"%s: I/O buffer too small\n", Cmdname);
  948.         exit(1);
  949.     }
  950.  
  951.     nread = read(fd, Bufp, blen);
  952.     if (Debug > 2)
  953.       fprintf(stderr,"%d of %d read.\n", nread, blen);
  954.     if (nread < 0)
  955.       croak(Tapename);
  956.     if (nread == 0)
  957.       die("%s: unexpected EOF.\n", Tapename);
  958.     if (nread != blen)
  959.       die("%s: wrong length.  Wanted %d but got %d\n",
  960.           Tapename, blen, nread);
  961.     return blen;
  962. }
  963.  
  964. static
  965. dump(b,l)                       /* print out a block */
  966. char *b;
  967. int l;
  968. {
  969.     int i;
  970.  
  971.     for (i = 0; l-- > 0; i++) {
  972.         if (i%32 == 0)
  973.           fprintf(stderr,"\n%5d:", i);
  974.         if (i%4 == 0)
  975.           fputc(' ',stderr);
  976.         fprintf(stderr,"%02x", *b++);
  977.     }
  978.     fputc('\n',stderr);
  979. }
  980.  
  981. static
  982. prtfst(f)                       /* print out fst info */
  983. register tapefst *f;
  984. {
  985.     int i;
  986.  
  987.     fprintf(stderr,"TAPEFST:\n");
  988.     fprintf(stderr," wp: %02x%02x\n", f->f_wp[0], f->f_wp[1]);
  989.     fprintf(stderr," rp: %02x%02x\n", f->f_rp[0], f->f_rp[1]);
  990.     fprintf(stderr," mode: %c%c\n", ETOL(f->f_mode[0]), ETOL(f->f_mode[1]));
  991.     fprintf(stderr," itcnt: %d\n", IBMTOSHORT(f->f_itcnt));
  992.     fprintf(stderr," fcl: %02x%02x\n", f->f_fcl[0], f->f_fcl[1]);
  993.     fprintf(stderr," recfm: %c\n", ETOL(f->f_recfm));
  994.     fprintf(stderr," flag: %02x\n", f->f_flag);
  995.     fprintf(stderr," lrecl: %d\n", IBMTOINT(f->f_lrecl));
  996.     fprintf(stderr," blkcnt: %d\n", IBMTOSHORT(f->f_blkcnt));
  997.     fprintf(stderr," date: %02x%02x%02x%02x%02x%02x\n", f->f_date[0],
  998.             f->f_date[1], f->f_date[2], f->f_date[3], f->f_date[4],
  999.             f->f_date[5]);
  1000.     fprintf(stderr," fop: %02x%02x%02x%02x\n", f->f_fop[0], f->f_fop[1],
  1001.             f->f_fop[2], f->f_fop[3]);
  1002.     fprintf(stderr," ablkcnt: %d\n", IBMTOINT(f->f_ablkcnt));
  1003.     fprintf(stderr," areccnt: %d\n", IBMTOINT(f->f_areccnt));
  1004.     fprintf(stderr," nlvl: %d\n", f->f_nlvl);
  1005.     fprintf(stderr," ptrs: %d\n", f->f_ptrs);
  1006.     fprintf(stderr," adate: %02x%02x%02x%02x%02x%02x\n", f->f_adate[0],
  1007.             f->f_adate[1], f->f_adate[2], f->f_adate[3], f->f_adate[4],
  1008.             f->f_adate[5]);
  1009.     fprintf(stderr," filler: "); dump(f->f_filler,sizeof(f->f_filler));
  1010.     fprintf(stderr," fn,ft,fm: ");
  1011.     for (i = 0; i < 18; i++)
  1012.       fputc(ETOL(f->f_fn[i]), stderr);
  1013.     fputc('\n',stderr);
  1014. }
  1015.  
  1016. #ifdef CMS
  1017. /* another Waterloo C defficiency */
  1018. perror(s)
  1019. char *s;
  1020. {
  1021.     fprintf(stderr,"%s: error.\n", s);
  1022. }
  1023. #endif CMS
  1024.  
  1025. /*
  1026.  * if Nametab is empty or given name matches an entry in it, return true.
  1027.  */
  1028. static int
  1029. in_nametab(fst)
  1030. tapefst *fst;
  1031. {
  1032.     register int i;
  1033.  
  1034.     if (Nametab == NULL)
  1035.       return 1;
  1036.     for (i = 0; i < Fcount; i++)
  1037.       if (bcmp(fst->f_fn, Nametab[i].name, sizeof(Nametab[0].name)) == 0)
  1038.         return 1;
  1039.     return 0;
  1040. }
  1041.  
  1042.  
  1043. /*
  1044.  * write files onto the tape.
  1045.  * - if Fname[i] is "-Fnn" then filename is in Fname[i+1] and it should be
  1046.  *   written recfm F lrecl nn.  Nn if ommitted is 80.
  1047.  * - if cooked (not Iflag) then records are delimitted by newlines and
  1048.  *   LTOE translation should be done.  Short recfm F records are padded
  1049.  *   with blanks.  Long ones are truncated (with a message).
  1050.  * - if raw (Iflag) then there are no record delimitters.  Just copy the
  1051.  *   data as is to tape blocks.  For recfm V,  the data is assumed to contain
  1052.  *   record lengths.  The max record length must be calculated for the fst.
  1053.  * - for CMS, recfm/lrecl are obtained with a stat(), so -F is not necessary.
  1054.  */
  1055.  
  1056. static
  1057. writetape()                     /* write a cms format tape */
  1058. {
  1059.     int i, tapefd, mode;
  1060. #undef NAME
  1061. #ifdef CMS
  1062.     char wlooname[50];
  1063.     strcpy(wlooname,Tapename);
  1064.     strcat(wlooname," (bin lrecl 65535");
  1065. # define NAME wlooname
  1066. #else
  1067. # define NAME Tapename
  1068. #endif !CMS
  1069.  
  1070.     mode = O_WRONLY|O_CREAT;
  1071.     mode |= (Rflag)? O_APPEND : O_TRUNC;
  1072.     if ((tapefd = open(NAME,mode,0644)) < 0)
  1073.       croak(Tapename);
  1074.     for (i = 0; i < Fcount; i++) {
  1075.         int lrecl = 0;
  1076.         int recfm = V;
  1077.  
  1078.         if (Fname[i][0] == '-' && Fname[i][1] == 'F') { /* check for -Fnn */
  1079.             recfm = F;
  1080.             lrecl = 80;
  1081.             sscanf(&Fname[i][2],"%d", &lrecl);
  1082.             ++i;
  1083.         }
  1084.         if (Debug)
  1085.           fprintf(stderr,"Writing %s recfm %c lrecl %d\n", Fname[i],
  1086.                   ETOL(recfm), lrecl);
  1087.         /* check accessability and get stat info for CMSN fst use */
  1088.         if (access(Fname[i], R_OK) < 0) {
  1089.             fprintf(stderr,"%s: can't access.  Skipping...\n", Fname[i]);
  1090.             continue;
  1091.         }
  1092.         tapedump(tapefd,i,lrecl,recfm);
  1093.     }
  1094.     close(tapefd);
  1095. }
  1096.  
  1097. /*
  1098.  * tapedump:  Dump file Fname[i] as Nametab[i] onto tapefd using given
  1099.  *  recfm and lrecl.  Check Iflag to see if we want a raw or cooked dump.
  1100.  */
  1101. static
  1102. tapedump(tapefd,i,lrecl,recfm)
  1103. int tapefd,i,lrecl;
  1104. char recfm;
  1105. {
  1106.     FILE *wf;
  1107.     int nread;
  1108.     int wfd;
  1109. #undef NAME
  1110. #ifdef CMS
  1111. # define NAME wlooname
  1112.     char wlooname[50];
  1113.     char *cmsexpn();
  1114.     fprintf(stderr,"cmsexpn: '%s'\n",cmsexpn(Fname[i]));
  1115.     if (stat(cmsexpn(Fname[i]), &St) < 0) {
  1116.         perror(Fname[i]);
  1117.         fprintf(stderr,"Skipping...\n");
  1118.         return;
  1119.     }
  1120.     recfm = St.st_recfm;
  1121.     lrecl = St.st_lrecl;
  1122.     sprintf(wlooname, "%s (recfm %c lrecl %d %s", Fname[i],
  1123.             St.st_recfm, St.st_lrecl, (Iflag)?"raw bin":"text");
  1124.     if (Debug)
  1125.       fprintf(stderr,"Fname is %s\n", wlooname);
  1126. #else
  1127. # define NAME Fname[i]
  1128. #endif !CMS
  1129.  
  1130.     Blocks = -1;                /* init tape block count */
  1131.     Recs = 0;                   /* and record count */
  1132.  
  1133.     if (Iflag) {                /* image dump */
  1134.         if ((wfd = open(NAME, O_RDONLY)) < 0) {
  1135.             perror(Fname[i]);
  1136.             fprintf(stderr,"Skipping...\n");
  1137.             return;
  1138.         }
  1139. #ifndef CMS
  1140.         if (recfm == F) {       /* recfm F */
  1141.             int bytes = 0;
  1142.  
  1143.             if (Debug)
  1144.               fprintf(stderr,"image dump recfm F\n");
  1145.             Maxrecl = lrecl;
  1146.             while ((nread = read(wfd,Bufp,TAPEDATA)) > 0) {
  1147.                 bytes += nread;
  1148.                 dumprec(tapefd,recfm,Bufp,nread);
  1149.             }
  1150.             Recs = bytes/Maxrecl;
  1151.         } else {                /* recfm V */
  1152.             int len;
  1153.  
  1154.             if (Debug)
  1155.               fprintf(stderr,"image dump recfm V\n");
  1156.             while (read(wfd,Bufp,2) == 2) { /* get lrecl */
  1157.                 len = IBMTOSHORT(Bufp);
  1158.                 if (Debug > 1)
  1159.                   fprintf(stderr,"read len [%d,%d] = %d\n", Bufp[0], Bufp[1],
  1160.                           len);
  1161.                 Maxrecl = (Maxrecl < len) ? len : Maxrecl;
  1162.                 if ((nread = read(wfd,Bufp+2,len)) != len) {
  1163.                     if (Debug)
  1164.                       fprintf(stderr,"len read = %d of %d\n", nread, len);
  1165.                     die("%s: not a V-format image.\n",Fname[i]);
  1166.                 }
  1167.                 dumprec(tapefd,recfm,Bufp,len+2);
  1168.             }
  1169.         }
  1170. #else
  1171.         /* for CMS image dumps,  both recfm F and V are done the same:
  1172.            Do a read with file opened raw which will return actual record
  1173.            length. For V, add that length to the dump record */
  1174.         while ((nread = read(wfd,Bufp+2,MAXBUF)) > 0) {
  1175.             if (recfm == F)
  1176.               dumprec(tapefd,recfm,Bufp+2,nread);
  1177.             else {
  1178.                 SHORTTOIBM(Bufp,nread);     /* length prefix */
  1179.                 dumprec(tapefd,recfm,Bufp,nread+2);
  1180.             }
  1181.             Maxrecl = (Maxrecl < nread) ? nread : Maxrecl;
  1182.         }
  1183.  
  1184. #endif CMS
  1185.         close(wfd);
  1186.     } else {                    /* cooked dump */
  1187.         if ((wf = fopen(NAME,"r")) == NULL) {
  1188.             perror(Fname[i]);
  1189.             fprintf(stderr,"Skipping...\n");
  1190.             return;
  1191.         }
  1192.         while (fgets(Bufp+2,MAXBUF,wf) != NULL) {
  1193.             if ((nread = strlen(Bufp+2) - 1) <= 0) { /* min CMS rec is 1 */
  1194.                 nread = 1;
  1195.                 Bufp[2] = ' ';
  1196.             }
  1197.             if (recfm == F) {   /* pad out to lrecl */
  1198.                 pad(Bufp+2,nread,lrecl);
  1199.                 nread = lrecl;
  1200.             }
  1201.             Maxrecl = (Maxrecl < nread) ? nread : Maxrecl;
  1202.             xlate(Bufp+2,nread); /* xlate to ebcdic */
  1203.             if (recfm == V) {   /* insert record length header */
  1204.                 SHORTTOIBM(Bufp,nread);
  1205.                 dumprec(tapefd,recfm,Bufp,nread+2);
  1206.             }
  1207.             else
  1208.                 dumprec(tapefd,recfm,Bufp+2,nread);
  1209.         }
  1210.         fclose(wf);
  1211.     }
  1212.     dumpeof(tapefd,i,recfm);
  1213. }
  1214.  
  1215.  
  1216. static
  1217. pad(b,l1,l2)
  1218. char *b;
  1219. register int l1,l2;
  1220. {
  1221.     if (l1 >= l2)
  1222.       return;
  1223.     for (; l1 < l2; l1++)
  1224.       b[l1] = ' ';
  1225. }
  1226.  
  1227. static
  1228. xlate(b,l)
  1229. register char *b;
  1230. register int l;
  1231. {
  1232. #ifndef CMS
  1233.     while (l-- > 0) {
  1234.         *b = LTOE(*b);
  1235.         b++;
  1236.     }
  1237. #endif !CMS
  1238. }
  1239.  
  1240. /*
  1241.  * write record into tapebuf[].  If this fills it,  flush it to fd
  1242.  * and begin filling next tapebuf[].
  1243.  */
  1244. static
  1245. dumprec(fd,recfm,b,l)
  1246. int fd;
  1247. char recfm;
  1248. char *b;
  1249. int l;
  1250. {
  1251.     if (Blocks == -1) {         /* first time thru, initialize */
  1252.         Tbrem = TAPEDATA;       /* amount of room left in tapebuf */
  1253.         Tbp = &Tapebuf[sizeof(tapehead)];
  1254.         bcopy(CMSh,Tapebuf,sizeof(tapehead));
  1255.         ((tapehead *)Tapebuf)->fmt = recfm;
  1256.         Blocks = 0;
  1257.     }
  1258.     ++Recs;
  1259.     if (Debug > 1) {
  1260.       fprintf(stderr,"dumprec: rec %5d len = %d blockno = %d rem = %d:",
  1261.               Recs, l, Blocks, Tbrem);
  1262.       dump(b,l);
  1263.     }
  1264.     while (l > 0) {
  1265.         if (Tbrem >= l) {       /* room for the full record */
  1266.             bcopy(b,Tbp,l);
  1267.             Tbrem -= l;
  1268.             Tbp += l;
  1269.             l = 0;
  1270.         } else {                /* have to spill over */
  1271.             bcopy(b,Tbp,Tbrem); /* copy what will fit */
  1272.             dumpbuf(fd,Tapebuf,sizeof(Tapebuf));
  1273.             l -= Tbrem;         /* subtract length we could fit */
  1274.             b += Tbrem;         /* increment data pointer this much */
  1275.             Tbp = &Tapebuf[sizeof(tapehead)];
  1276.             Tbrem = TAPEDATA;
  1277.             Blocks++;
  1278.         }
  1279.     }
  1280. }
  1281.  
  1282. static
  1283. dumpeof(fd,i,recfm)
  1284. int fd,i;
  1285. char recfm;
  1286. {
  1287.     struct stat stbuf;
  1288.     struct tm *tm;
  1289.     tapehead *th = (tapehead *)Tapebuf;
  1290.     tapefst *t = (tapefst *)&Tapebuf[sizeof(tapehead)];
  1291.  
  1292.     if (Tbrem < TAPEDATA)       /* flush pending data */
  1293.       dumpbuf(fd,Tapebuf,TAPEDATA-Tbrem+sizeof(tapehead));
  1294.     if (Debug)
  1295.       fprintf(stderr,"dumpeof: blocks %d, recs %d, maxrecl %d\n",
  1296.               Blocks, Recs, Maxrecl);
  1297. #ifndef CMS
  1298.     if (stat(Fname[i],&stbuf) < 0)
  1299.       croak("dumpeof");
  1300.     /* fill in tapefst -- both old and new ("alternate") fields */
  1301.     bzero(t,sizeof(*t));
  1302.     t->f_fm[0] = t->f_mode[0] = LTOE('A');
  1303.     t->f_fm[1] = t->f_mode[1] = LTOE('1');
  1304.     SHORTTOIBM(t->f_itcnt,Recs);
  1305.     INTTOIBM(t->f_areccnt,Recs);
  1306.     t->f_recfm = th->fmt;
  1307.     th->fmt = N;                /* change to an eof header */
  1308.     INTTOIBM(t->f_lrecl,Maxrecl);
  1309.     SHORTTOIBM(t->f_blkcnt,Blocks);
  1310.     INTTOIBM(t->f_ablkcnt,Blocks);
  1311.     tm = localtime(&stbuf.st_mtime);
  1312. /* old date format is odd:  year is ebcdic,  everything else is packed */
  1313.     t->f_date[0] = 0xf0 | (tm->tm_year/10)&0x0f; /* ebcdic year tens */
  1314.     t->f_date[1] = 0xf0 | (tm->tm_year%10)&0x0f; /* ebcdic year ones */
  1315.     t->f_adate[0] = PACK(tm->tm_year);
  1316.     t->f_adate[1] = t->f_date[2] = PACK(tm->tm_mon+1);
  1317.     t->f_adate[2] = t->f_date[3] = PACK(tm->tm_mday);
  1318.     t->f_adate[3] = t->f_date[4] = PACK(tm->tm_hour);
  1319.     t->f_adate[4] = t->f_date[5] = PACK(tm->tm_min);
  1320.     t->f_adate[5] = PACK(tm->tm_sec);
  1321.     bcopy(Nametab[i].name,t->f_fn,sizeof(Nametab[0].name));
  1322. #else
  1323.     /* stat already done into St */
  1324.     bzero(t,sizeof(*t));
  1325.     t->f_fm[0] = t->f_mode[0] = St.st_fmode[0];
  1326.     t->f_fm[1] = t->f_mode[1] = St.st_fmode[1];
  1327.     SHORTTOIBM(t->f_itcnt,St.st_size);
  1328.     INTTOIBM(t->f_areccnt,St.st_size);
  1329.     t->f_recfm = th->fmt;
  1330.     th->fmt = N;                /* change to an eof header */
  1331.     INTTOIBM(t->f_lrecl,Maxrecl);
  1332.     SHORTTOIBM(t->f_blkcnt,Blocks);
  1333.     INTTOIBM(t->f_ablkcnt,Blocks);
  1334. /* old date format is odd:  year is ebcdic,  everything else is packed */
  1335.     bcopy(St.st_mtime,t->f_adate,sizeof(t->f_adate));
  1336.     bcopy(&t->f_adate[1],&t->f_date[2], sizeof(t->f_date)-2);
  1337.     t->f_date[0] = HI(t->f_adate[0]) | 0xf0;
  1338.     t->f_date[1] = LO(t->f_adate[0]) | 0xf0;
  1339.     bcopy(St.st_fname,t->f_fn,sizeof(St.st_fname)+sizeof(St.st_ftype));
  1340. #endif CMS
  1341.     dumpbuf(fd,Tapebuf,sizeof(tapehead)+sizeof(tapefst));
  1342.     if (Tflag)
  1343.       prinfo(t);
  1344. }
  1345.  
  1346. static
  1347. dumpbuf(fd,b,l)
  1348. int fd;
  1349. char *b;
  1350. int l;
  1351. {
  1352.     if (Debug > 1)
  1353.       fprintf(stderr,"dumping block %d, len %d.\n", Blocks, l);
  1354.     if (Fflag) {                /* write readtape(l) count */
  1355.         u_char clen[2];
  1356.  
  1357.         clen[1] = l >> 8;       /* vax byte order */
  1358.         clen[0] = l & 0xff;
  1359.         if (write(fd,clen,2) < 0)
  1360.           croak("dumpbuf");
  1361.     }
  1362.     if (write(fd,b,l) < 0)      /* flush it */
  1363.       croak("dumpbuf");
  1364.     if (Debug > 2) {
  1365.         fprintf(stderr,"data: ");
  1366.         dump(b,l);
  1367.     }
  1368. }
  1369.  
  1370. #ifdef CMS
  1371. static char *
  1372. cmsexpn(f)                      /* fudge file name for wloo C stat(), etc. */
  1373. char *f;
  1374. {
  1375.     static char e[21];
  1376.     char *ep = e;
  1377.     int i;
  1378.  
  1379.     /* filename */
  1380.     for (i = 0; i < 8 && isalnum(*f); i++,f++,ep++)
  1381.       *ep = islower(*f)? toupper(*f) : *f;
  1382.     *ep++ = ' ';
  1383.     while (isalnum(*f))         /* skip more than 8 char filename */
  1384.       f++;
  1385.     if (*f == '\0' || *f == '(') { /* filetype missing */
  1386.         strcat(ep,"FILE");
  1387.         return e;
  1388.     }
  1389.     /* filetype */
  1390.     for (f++, i = 0; i < 8 && isalnum(*f); i++,f++,ep++)
  1391.       *ep = islower(*f)? toupper(*f) : *f;
  1392.     *ep++ = ' ';
  1393.     while (isalnum(*f))         /* skip more than 8 char filetype */
  1394.       f++;
  1395.     if (*f == '\0' || *f == '(') { /* filemode missing */
  1396.         ep[-1] = '\0';             /* clobber the trailing blank */
  1397.         return e;
  1398.     }
  1399.     /* filemode */
  1400.     for (f++, i = 0; i < 2 && isalnum(*f); i++,f++,ep++)
  1401.       *ep = islower(*f)? toupper(*f) : *f;
  1402.     *ep = '\0';
  1403.     return e;
  1404. }
  1405. #endif CMS
  1406.  
  1407.  
  1408. /*
  1409.  * various ways to die
  1410.  */
  1411. static
  1412. die(s,a1,a2,a3,a4,a5)
  1413. char *s;
  1414. {
  1415.     fprintf(stderr,s,a1,a2,a3,a4,a5);
  1416.     exit(1);
  1417. }
  1418.  
  1419. static
  1420. croak(s)
  1421. char *s;
  1422. {
  1423.     perror(s);
  1424.     exit(1);
  1425. }
  1426.  
  1427. SHAR_EOF
  1428. fi
  1429. if test -f 'ebcdic.c'
  1430. then
  1431.     echo shar: "will not over-write existing file 'ebcdic.c'"
  1432. else
  1433. cat << \SHAR_EOF > 'ebcdic.c'
  1434. /* $Header: ebcdic.c,v 1.1 86/07/18 10:44:26 alan Rel $
  1435.  * ebcdic to ascii translation based on values use on Columbia Computer
  1436.  * Center IBM mainframes.  This may or may not agree with your definition
  1437.  * of the mapping.  (Derived from USLIB MACLIB Y member ASCII)
  1438.  *
  1439.  * Alan Crosswell,  Columbia University
  1440.  * $Log:    ebcdic.c,v $
  1441.  * Revision 1.1  86/07/18  10:44:26  alan
  1442.  * Initial revision
  1443.  * 
  1444.  */
  1445.  
  1446. char etoa[256] = {
  1447.     0x00,0x01,0x02,0x03,0x00,0x09,0x00,0x7f,
  1448.     0x00,0x00,0x00,0x0b,0x0c,0x0d,0x0e,0x0f,
  1449.     0x10,0x11,0x12,0x13,0x00,0x00,0x08,0x00,
  1450.     0x18,0x19,0x00,0x00,0x1c,0x1d,0x1e,0x1f,
  1451.     0x00,0x00,0x00,0x00,0x00,0x0a,0x17,0x1b,
  1452.     0x00,0x00,0x00,0x00,0x00,0x05,0x06,0x07,
  1453.     0x00,0x00,0x16,0x00,0x00,0x00,0x00,0x04,
  1454.     0x00,0x00,0x00,0x00,0x14,0x15,0x00,0x1a,
  1455.     0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  1456.     0x00,0x00,0x00,0x2e,0x3c,0x28,0x2b,0x7c,
  1457.     0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  1458.     0x00,0x00,0x21,0x24,0x2a,0x29,0x3b,0x5e,
  1459.     0x2d,0x2f,0x00,0x00,0x00,0x00,0x00,0x00,
  1460.     0x00,0x00,0x00,0x2c,0x25,0x00,0x3e,0x3f,
  1461.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  1462.     0x00,0x60,0x3a,0x23,0x40,0x27,0x3d,0x22,
  1463.     0x00,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
  1464.     0x68,0x69,0x00,0x00,0x00,0x00,0x00,0x00,
  1465.     0x00,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,
  1466.     0x71,0x72,0x00,0x00,0x00,0x00,0x00,0x00,
  1467.     0x00,0x7e,0x73,0x74,0x75,0x76,0x77,0x78,
  1468.     0x79,0x7a,0x00,0x00,0x00,0x5b,0x00,0x00,
  1469.     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  1470.     0x00,0x00,0x00,0x00,0x00,0x5d,0x00,0x00,
  1471.     0x7b,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
  1472.     0x48,0x49,0x00,0x00,0x00,0x00,0x00,0x00,
  1473.     0x7d,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,
  1474.     0x51,0x52,0x00,0x00,0x00,0x00,0x00,0x00,
  1475.     0x5c,0x00,0x53,0x54,0x55,0x56,0x57,0x58,
  1476.     0x59,0x5a,0x00,0x00,0x00,0x00,0x00,0x00,
  1477.     0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
  1478.     0x38,0x39,0x00,0x00,0x00,0x00,0x00,0x00,
  1479. };
  1480.  
  1481. char atoe[256] = {
  1482.     0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f,
  1483.     0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f,
  1484.     0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26,
  1485.     0x18,0x19,0x3f,0x27,0x1c,0x1d,0x1e,0x1f,
  1486.     0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d,
  1487.     0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61,
  1488.     0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,
  1489.     0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f,
  1490.     0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,
  1491.     0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,
  1492.     0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6,
  1493.     0xe7,0xe8,0xe9,0xad,0xe0,0xbd,0x5f,0x6d,
  1494.     0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
  1495.     0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96,
  1496.     0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6,
  1497.     0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0x07,
  1498. /* repeat it over again for 8-bit ascii with parity set */
  1499.     0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f,
  1500.     0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f,
  1501.     0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26,
  1502.     0x18,0x19,0x3f,0x27,0x1c,0x1d,0x1e,0x1f,
  1503.     0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d,
  1504.     0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61,
  1505.     0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,
  1506.     0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f,
  1507.     0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,
  1508.     0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,
  1509.     0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6,
  1510.     0xe7,0xe8,0xe9,0xad,0xe0,0xbd,0x5f,0x6d,
  1511.     0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
  1512.     0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96,
  1513.     0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6,
  1514.     0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0x07,
  1515. };
  1516.  
  1517. SHAR_EOF
  1518. fi
  1519. exit 0
  1520. #    End of shell archive
  1521.